package com.hulk.boot.common.util;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.CompactWriter;
import com.thoughtworks.xstream.io.xml.DomDriver;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;


/**
 * @author 
 *
 */
public class XStreamUtil {
    private static final Logger log = LoggerFactory.getLogger(XStreamUtil.class);

    /**
     * 使用给定的 XStream 实例序列化 XML ，并且带上给定编码的 head 信息
     * @param obj 待序列化的对象
     * @param xStream XStream 实例
     * @param charSet 编码
     * @return XML
     */
    public static String toXmlWithHead(Object obj, XStream xStream, String charSet) {
        StringBuilder sBuffer = new StringBuilder();
        String xmlHead = "<?xml version=\"1.0\" encoding=\""+charSet+"\"?>";
        sBuffer.append(xmlHead).append(toXML(obj, xStream));
        return sBuffer.toString();
    }


    /**
     * java bean 转化为xml
     * 
     * @param object  bean
     * @param beanClasses   需要转化成xml的bean对象的class
     * @return  string of xml
     * @throws XMLParseException 
     */

    public static String toXml(Object object) throws RuntimeException {
        if (object == null) {
            log.warn("object is null!");
            throw new RuntimeException("object is null");
        }
        XStream xstream = new XStream();
        String xml;
        try {
            xml = xstream.toXML(object);
        } catch (RuntimeException e) {
            log.error("object:" + object.getClass(), e);
            throw new RuntimeException("object:" + object.getClass(),e);
        }
        return xml;
    }
    
    /**
	 * java bean转换为XML字符串
	 * @param object 要转换的bean对象
	 * @param clazz 注解class类
	 * @param isAonn  是否带注解
	 * @return 转换成功的xml字符串
	 */
	public static String toXml(Object object, Class<?> clazz, boolean isAonn) {
		XStream xstream = new XStream(new DomDriver());
		xstream.setMode(XStream.NO_REFERENCES);
		xstream.autodetectAnnotations(true);//去掉不用的属性
		if (isAonn) {
			xstream.processAnnotations(clazz);
		}
		String result = xstream.toXML(object);
		return result;
	}
    /**
     * 使用给定的 XStream 实例序列化 XML
     * @param obj 待序列化的对象
     * @param xStream XStream 实例
     * @return XML
     */
    public static String toXML(Object obj, XStream xStream) {
        StringWriter sw = new StringWriter();
        CompactWriter writer = new CompactWriter(sw);
        try {
            xStream.marshal(obj, writer);
        } finally {
            writer.close();
        }
        return sw.toString();
        // Don't know why replace these special characters
        //
//        String str = sw.toString();
//        return str.replaceAll("__", "_").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"");
    }

	@SuppressWarnings("unchecked")
	public static <T>T toBean(String xmlStr,Class<T> cls){
		XStream xstream=new XStream(new DomDriver());
		xstream.processAnnotations(cls);
		T obj=(T)xstream.fromXML(xmlStr);
		return obj;
	}
	
	 /**
     * xml 转化为java bean
     * 
     * @param xml 
     * @return  java bean
     * @throws XMLParseException 
     */

    @SuppressWarnings("unchecked")
    public static <T> T toObject(String xml) throws RuntimeException {
        if (xml == null) {
            log.warn("xml is null!");
            throw new RuntimeException("xml content is null");
        }
        XStream xstream = new XStream();
        T object;
        try {
            object = (T) xstream.fromXML(xml);
        } catch (RuntimeException e) {
            log.error("xml:" + xml, e);
            throw new RuntimeException("xml:" + xml, e);
        }
        return object;
    }

	/**
	 * xml字符串转换为java bean对象
	 * @param xml 传入的xml字符串
	 * @return 转换成功的java bean对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fromXml(String xml) {
		XStream xstream = new XStream();
		T result = (T) xstream.fromXML(xml);
		return result;
	}
	
	
	
	/**
	 * xml字符串转换为java bean对象
	 * @param xml 传入的xml字符串
	 * @param mapAlias 别名集合
	 * @return 转换成功的java bean对象
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fromXml(String xml, Map<String, Class<?>> mapAlias) {
		XStream xstream = new XStream();
		Set<String> keys = mapAlias.keySet();
		for (String key : keys) {
			xstream.alias(key, mapAlias.get(key));
		}
		T result = (T) xstream.fromXML(xml);
		return result;
	}
	
    
    /**
     * 使用给定的 XStream 实例反序列化 XML
     * @param xml XML
     * @param xStream XStream 实例
     * @return object. null if xml is blank
     */
    @SuppressWarnings("unchecked")
	public static <T> T fromXML(String xml, XStream xStream) {
        if (StringUtils.isBlank(xml)) {
            return null;
        }
        //noinspection unchecked
        return (T) xStream.fromXML(xml);
    }

    /**
     * 使用给定的 XStream 实例和 XML 填充给定的对象
     * <br/>
     * 此方法会直接修改入参 bean 中的属性。谨慎使用此方法，尽可能使用创建新实例的 {@link #fromXML(String, com.thoughtworks.xstream.XStream)}
     *
     * @param xml XML
     * @param bean 待填充的对象
     * @param xStream XStream 实例
     * @return bean itself. null if bean is null or xml is blank
     */
    @SuppressWarnings("unchecked")
	public static <T> T fillByXml(String xml, T bean, XStream xStream) {
        if (null == bean || StringUtils.isBlank(xml)) {
            return null;
        }
        //noinspection unchecked
        return (T) xStream.fromXML(xml, bean);
    }

    
    /**
     * 对于xstream的annotation的说明
     * 将下面的annotation配置在java bean的属性或者类名上
     * 可以参考本项目的test目录中的ConfigCenters.java
     * @XStreamAlias("xx")
     * 设置xml中element的别名
     * @XStreamAsAttribute 
     * 将该字段设为根标签的attribute
     * @XStreamImplicit(itemFieldName="XX")
     * 将List的根节点去掉和改变列表名字
     * @XStreamOmitField  
     * 忽略该属性
     * @param object   java bean
     * @param beanClasses 
     * @return  xml of bean
     * @throws XMLParseException 
     */

    public static String toXmlByAnnotation(Object object) throws RuntimeException {
        if (object == null) {
            log.warn("object is null!");
            throw new RuntimeException("object is null");
        }
        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        return xstream.toXML(object);
    }

    /**
     * 
     * @param xml toXmlByAnnotation产生的xml对应
     * @param beanClasses
     * @return
     * @throws XMLParseException 
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T toObjectByAnnotation(String xml, Class beanClass) throws RuntimeException {
        if (beanClass == null) {
            log.warn("beanClasses is null!");
            return null;
        }
        if (xml == null) {
            log.warn("xml is null!");
            return null;
        }
        XStream xstream = new XStream();
        xstream.processAnnotations(beanClass);
        T object;
        try {
            object = (T) xstream.fromXML(xml);
        } catch (RuntimeException e) {
            log.error("xml:" + xml, e);
            throw new RuntimeException("xml:" + xml,e);

        }
        return object;
    }

    /**
	 * 注册列名，使用字段名称的大写
	 *
	 * @param clazz
	 *            需要转换的类
	 * @param xstream
	 *            注册到该xstream
	 */
	public static void aliasFieldUseUpperCase(Class<?> clazz, XStream xstream) {
		Field[] fields = clazz.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			xstream.aliasField(fields[i].getName().toUpperCase(), clazz, fields[i].getName());
		}
	}
	
	public static void aliasField(Class<?> clazz, XStream xstream) {
		Field[] fields = clazz.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			xstream.aliasField(fields[i].getName(), clazz, fields[i].getName());
		}
	}
	

	/**
	 * 注册属性，使用字段名称的大写
	 *
	 * @param clazz
	 *            需要转换的类
	 * @param xstream
	 *            注册到该xstream
	 */
	public static void aliasAttributeUseUpperCase(Class<?> clazz, XStream xstream) {
		Field[] fields = clazz.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			xstream.aliasAttribute(clazz, fields[i].getName(), fields[i].getName().toUpperCase());
		}
	}

	/**
	 * 注册属性和列名，使用字段名称的大写
	 *
	 * @param clazz
	 *            需要转换的类
	 * @param xstream
	 *            注册到该xstream
	 * @param fieldNames
	 *            需要注册为列名的字段名称
	 */
	public static void aliasAttributeAndFieldUseUpperCase(Class<?> clazz, XStream xstream, String... fieldNames) {
		Field[] fields = clazz.getDeclaredFields();
		String fieldName;
		flag: for (int i = 0; i < fields.length; i++) {
			fieldName = fields[i].getName();
			for (int j = 0; j < fieldNames.length; j++) {
				if (fieldNames[j].equals(fieldName)) {
					xstream.aliasField(fieldName.toUpperCase(), clazz, fieldName);
					continue flag;
				}
			}
			xstream.aliasAttribute(clazz, fieldName, fieldName.toUpperCase());
		}
	}


    

}
